package com.db.router.strategy;

import javax.annotation.Resource;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

public class ConsistentHashing {
    

    private final TreeMap<Integer, Node> hashCircle = new TreeMap<>();
    private final int virtualNums; // 虚拟节点数

    public ConsistentHashing(Node[] nodes, int virtualNums) {
        this.virtualNums = virtualNums;
        // 初始化一致性hash环
        for (Node node : nodes) {
            // 创建虚拟节点
            add(node);
        }
    }

    /**
     * 添加服务器节点
     *
     * @param node the server
     */
    public void add(Node node) {
        for (int i = 0; i < virtualNums; i++) {
            hashCircle.put(hash(node.toString() + i), node);
        }
    }

    /**
     * 删除服务器节点
     *
     * @param node the server
     */
    public void remove(Node node) {
        for (int i = 0; i < virtualNums; i++) {
            hashCircle.remove(hash(node.toString() + i));
        }
    }

    /**
     * 获取服务器节点
     *
     * @param key the key
     * @return the server
     */
    public Node getNode(String key) {
        if (key == null || hashCircle.isEmpty()){
            return null;
        }
        int hash = hash(key);
        if (!hashCircle.containsKey(hash)) {
            // 未命中对应的节点,找Hash环中最近的节点
            Map.Entry<Integer, Node> higherEntry = hashCircle.higherEntry(hash);
            return higherEntry == null ? hashCircle.firstEntry().getValue() : higherEntry.getValue();
        }
        return hashCircle.get(hash);
    }

    /**
     * 获取服务器节点
     *
     * @param hashValue 哈希索引
     * @return the server
     */
    public Node getNode(int hashValue) {
        if (!hashCircle.containsKey(hashValue)) {
            // 未命中对应的节点,找Hash环中最近的节点
            SortedMap<Integer, Node> tailMap = hashCircle.tailMap(hashValue);
            hashValue = tailMap.isEmpty() ? hashCircle.firstKey() : tailMap.firstKey();
        }
        return hashCircle.get(hashValue);
    }

    private int hash(String key) {
        final int p = 16777619;
        int hash = (int) 2166136261L;
        for (int i = 0; i < key.length(); i++) {
            hash = (hash ^ key.charAt(i)) * p;
        }
        hash += hash << 13;
        hash ^= hash >> 7;
        hash += hash << 3;
        hash ^= hash >> 17;
        hash += hash << 5;

        // 如果算出来的值为负数则取其绝对值
        return Math.abs(hash);
    }


    /**
     * 集群节点的机器地址
     */
    public static class Node {
        private final int dbIndex;
        private final int tbIndex;

        public Node(int dbIndex, int tbIndex) {
            this.dbIndex = dbIndex;
            this.tbIndex = tbIndex;
        }

        public int getDbIndex() {
            return dbIndex;
        }

        public int getTbIndex() {
            return tbIndex;
        }

        @Override
        public String toString() {
            return "db:"+dbIndex + "--" + "tb:"+tbIndex;
        }

    }
}
